package org.nf.web.servlet;

import cn.hutool.core.exceptions.ExceptionUtil;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.nf.web.config.Configure;
import org.nf.web.mapping.SimplerHandlerMapping;
import org.nf.web.view.DefaultView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;

/**
 * @Author czl
 * @Date 2024-05-14
 * 请求总控器，负责接收所有的请求，然后根据请求地址
 * 分发给不同的后端控制器（Controller）
 * 当url-pattern设置为 “/” 时，会覆盖默认的DefaultServlet
 * 所有的web服务器都会有一个默认的Servlet
 * 这个Servlet,专门用于处理静态资源
 */
public class DispatcherServlet extends HttpServlet {
    /**
     * HandlerMapping集合，负责查找不同Controller
     */
    private List<HandleMapping> handlerMappings = new ArrayList<>();

    /**
     * HandlerAdapter集合，负责调用Controller
     */
    private List<HandlerAdapter> handlerAdapters = new ArrayList<>();

    /**
     * 异常解析器集合
     */
    private List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        ServletContext sc = config.getServletContext();
        //从servletContext中获取配置对象
        Configure configure = (Configure) sc.getAttribute("configure");
        //初始化HandlerMapping
        initHandlerMapping(configure);
        //初始化HandlerInvoke
        initHandlerAdapter();
        //初始化异常解析器
        initExceptionResolver(configure);
    }

    /**
     * 初始化所有的HandlerAdapter
     */
    private void initHandlerAdapter() {
        for(HandlerAdapter adapter : ServiceLoader.load(HandlerAdapter.class)) {
            handlerAdapters.add(adapter);
        }
    }

    /**
     * 初始化所有的HandlerMapping
     */
    private void initHandlerMapping(Configure configure) {
        for(HandleMapping hm : ServiceLoader.load(HandleMapping.class)) {
            //初始化
            hm.init(configure);
            //添加到集合中
            handlerMappings.add(hm);
        }
    }


    private void initExceptionResolver(Configure configure){
        for (HandlerExceptionResolver resolver : ServiceLoader.load(HandlerExceptionResolver.class)){
            resolver.init(configure);
            exceptionResolvers.add(resolver);
        }
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletApi servletApi = new ServletApi(req, resp);
        //根据请求获取可以处理请求的handler
        Object handler = getHandler(req);
        //如果handler不为空则交给HandlerInvoker去调用
        if(handler != null) {
            //将Controller交给HandlerInvoke负责去调用
            //注意：此时的controller对象有可能是Class对象也有可能是一个Method对象
            //但是DispatcherServlet是不能识别它是哪一个对象，所以不能强转为Class，
            //必须要有一种机制去适配这些不同的controller
            //找到合适匹配的adapter
            HandlerAdapter ha = getAdapter(handler);
            Object viewObj;
            try {
                //调用handler的方法处理请求
                viewObj =ha.handler(handler,servletApi);

            } catch (Exception e) {
                //处理全局异常
                viewObj = handleException(e);
                //渲染视图
                render(viewObj,servletApi);
            }
        } else {
            //根据Servlet的名称进行转发
            req.getServletContext().getNamedDispatcher("default").forward(req, resp);
        }

    }

    /**
     * 根据HandlerMapping查找合适的handler
     * 这个handler可能是Class也可能是Method对象
     * @return
     */
    private Object getHandler(HttpServletRequest req) {
        for(HandleMapping mapping : handlerMappings) {
            Object handler = mapping.getHandler(req);
            if(handler != null) {
                return handler;
            }
        }
        return null;
    }

    /**
     * 根据handler找到合适的适配器
     * @param handler
     * @return
     */
    private HandlerAdapter getAdapter(Object handler) {
        for(HandlerAdapter adapter: handlerAdapters) {
            if(adapter.supports(handler)) {
                return adapter;
            }
        }
        throw new RuntimeException("HandlerAdapter not found.");
    }

    /**
     * 异常处理
     * @param e 产生的异常对象
     * @return 视图
     */
    private View handleException(Exception e){
        Throwable t = ExceptionUtil.getRootCause(e);
        t.printStackTrace();
        View view = null;
        for (HandlerExceptionResolver resolver: exceptionResolvers){
            view = resolver.resolveException(t);
            if (view != null){
                break;
            }
        }
        return view;
    }



    /**
     * 渲染视图对象
     * @param object 由适配器返回的视图对象
     */
    private void render(Object object, ServletApi api)throws ServletException, IOException{
        if(object != null) {
            //如果是View接口的实例，则强转后执行渲染
            //否则使用默认视图来处理响应
            if(object instanceof View view) {
                view.render(api);
            } else {
                new DefaultView(object).render(api);
            }
        }
    }
}